package eightDataType;

import org.apache.log4j.Logger;
import org.junit.Test;
import utils.PrintUtil;
import utils.ThreadUtils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * @author Ajie
 * @date 2019-12-13
 * @function
 */
public class ByteUtil {
    private static final Logger logger = Logger.getLogger(ByteUtil.class);
    public static void main(String[] args) {
//        String s = hexToAsciiString("00");
//        String s = hexToAsciiString("66635F31636E5F33");//fc_1cn_3
//        String s = hexToAsciiString("2D2D3230352A2A313030383100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");//--23R¢£3
        String s = hexToAsciiString("2D2D3230352A2A3130303831");//--23R¢£3
//        String s = hexToAsciiString("66635F31636E5F3300000000");//fc_1cn_3
//        String s = hexToAsciiString("66635F31636E5F330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");//fc_1cn_3
//        String s = hexToAsciiString("66635F31636E5F3366635F31636E5F3366635F31636E5F3300000000000000000000000000000000000000000000000000000000000000000000000000000000");//fc_1cn_3
//        String s = hexToAsciiString("66635f31636e5f33000");//fc_1cn_3
//        hexToAsciiString("66635f31636e5f330000");//fc_1cn_3
//        hexToAsciiString("66635f31636e5f33");//fc_1cn_3

        System.out.println("ByteUtil:main:hexToAsciiString res:" + s);
        System.out.println("ByteUtil:main:------------");
        ThreadUtils.sleep(50);
        byte[] ac = {1,2,3,4};
      ac[1] = 5%128;

      PrintUtil.print(hexStrToBytes("5A"));
//        System.out.println(hexToByte("5A"));
//
//        short abc = 1234;
//        byte[] bytes = shortToBytes(abc);
//        PrintUtil.print(bytes);
//
//        System.out.println("short to bytes");
        byte b = -1 ;
        try {
            b = hexToByte("FF");
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        System.out.println("hexToByte "+b);

//        byte[] by = hexToByteArray("F04F01EFEE");
//        byte[] by = hexToByteArray("F0 4F 01 EF EE");
//        byte[] by = hexToByteArray("F04F0806");
        byte[] by = hexStrToBytes("0000EFEE");
        for (byte b1:by) {
            System.out.print("，"+b1);
        }

    }

    /**
     * 要将十六进制数字符串转换为 ASCII 字符串，可以使用以下步骤：
     *
     * 1.使用 String.trim() 方法去掉字符串开头和结尾的空格。
     * 2.使用 String.replaceAll("0*$", "") 方法去掉字符串末尾的零。
     *
     * 3.使用 String.split("(?<=\\G..)") 方法将字符串分割为由两个字符组成的数组。
     * 4.使用 Integer.parseInt(hex, 16) 将十六进制数转换为十进制数。
     * 5.使用 Character.toString((char)decimal) 将十进制数转换为字符。
     * 6.如果要转换多个十六进制数，可以使用循环来遍历每个十六进制数并逐个转换。
     *
     * 测试样例：
     *         hexToAsciiString("66635f31636e5f33000");//fc_1cn_3
     *         hexToAsciiString("66635f31636e5f330000");//fc_1cn_3
     *         hexToAsciiString("66635f31636e5f33");//fc_1cn_3
     *
     * TODO String s = hexToAsciiString("2D2D3230352A2A3130303831");//--23R¢£3 有问题，暂时不知为什么？
     * //正确结果：：：--205**10081
     * @param hex
     */
    public static String hexToAsciiString(String hex) {
        System.out.println("ByteUtil:hexToAscii:strat:"+hex);
        if (hex == null || hex.length()<1) return null;
        //String hex = "0x01000300";
        hex = hex.trim();  // 去掉开头和结尾的空格
        if (hex == null || hex.length()<1) return null;//过滤有效

        hex = hex.replaceAll("(?<=^|[^0])0*", "");  // 去掉非前导零的零
        if (hex == null || hex.length()<1) return null;//过滤有效

//            String[] hexArray = hex.split("(?<=\\G..)");  // 分割成由两个字符组成的数组
        String[] hexArray = strSpilt2CharArray(hex);  // 分割成由两个字符组成的数组
        StringBuilder sb = new StringBuilder();

        for (String h : hexArray) {
            int decimal = Integer.parseInt(h, 16);
            sb.append(Character.toString((char)decimal));
        }

        try {

        }catch (NumberFormatException e){//java mac 上可以正常分割字符。android beeboxes 设备不能正常分割字符。
            e.printStackTrace();
        }

        return sb.toString();
    }

    @Test
    public void split2CharsArray() {
      System.out.println("split2CharsArray:");
        String[] strings = strSpilt2CharArray("66635F31636E5F33");
        PrintUtil.print(strings);
        String[] strings2 = strSpilt2CharArray("66635F31636E5F33😄");
        PrintUtil.print(strings2);
    }

    /**
     *  暂时替代 hex.split("(?<=\\G..)");  // 分割成由两个字符组成的数组
     *  java mac 上可以正常分割字符。android beeboxes 设备不能正常分割字符。
     * @param str
     */
    public static String[] strSpilt2CharArray(String str) {
        if (str == null) return null;
        int length = str.length();
        System.out.println("ByteUtil:spilt2chars:len:"+length);

        boolean lastOne = (length%2 == 1);//暂不处理
        String arr[]=new String[length /2];

        for (int i = 0; i < arr.length; i++) {
            arr[i] = String.valueOf(str.charAt(i*2)) + String.valueOf(str.charAt(i*2 + 1));
        }
        return arr;
    }


    /**
     * byte 转 无符号 int  突破 byte 128限制
     * @param ori
     * @return
     */
    public static int byteToIntNoSymbol(byte ori){
        int intHeigh = ((Byte) ori).intValue();
        return intHeigh&0xFF;
    }

    public static short bytesToShort(byte[] bytes) {
        return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getShort();
    }
    public static byte[] shortToBytes(short value) {
        return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(value).array();
    }

    @Test
    public void testByteToHex(){
       byte[] data = new byte[]{0x01, 0x05, 0x00, 0x02, (byte) 0xFF, 0x00, (byte) 0x2D, (byte) 0xFA};
        System.out.println("byte: "+new String(data));
        System.out.println("testByteToHex: "+bytesToHex(data));
    }

    /**
     * 字节转十六进制
     * @param b 需要进行转换的byte字节
     * @return  转换后的Hex字符串
     */
    public static String byteToHex(byte b){
        String hex = Integer.toHexString(b & 0xFF);
        if(hex.length() < 2){
            hex = "0" + hex;
        }
        return hex;
    }

    public static String byteToHex(byte[] b){
        if (b==null) return  null;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i <b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if(hex.length() < 2){
                hex = "0" + hex;
            }
            sb.append(hex);
        }
        return sb.toString();
    }

    @Test
    public void testbytesToHex(){
        String s = bytesToHex(new byte[]{43});
        logger.info("bytesToHex: "+s);
    }

    /**
     * 字节数组转16进制
     * @param bytes 需要转换的byte数组
     * @return  转换后的Hex字符串
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if(hex.length() < 2){
                sb.append(0);
            }
            sb.append(hex);
        }
        return sb.toString();
    }


    //TODO 最佳实践。2024-06-19 待测chatGPT 优化下面的 2 个方法得来。ByteUtilTest有样例。
    /**
     * 将十六进制字符串转换为字节数组
     * @param hexStr 待转换的十六进制字符串
     * @return 转换后的字节数组
     */
    public static byte[] hexStrToBytes(String hexStr) {
        //public static byte[] hexStrToBytes0(String hexStr) throws IllegalArgumentException{
        if (hexStr == null || hexStr.isEmpty()) {
            System.err.println("输入的参数异常:"+hexStr);
            return null;
        }

        // 移除所有空格
        hexStr = hexStr.replaceAll(" ", "");

        // 检查字符串是否只包含有效的十六进制字符
        if (!hexStr.matches("[0-9A-Fa-f]+")) {
//            throw new IllegalArgumentException("Invalid hexadecimal string");
            System.err.println("输入不是有效的16进制字符串:"+hexStr);
            return null;
        }

        // 处理奇数长度的字符串
        if (hexStr.length() % 2 != 0) {
            hexStr = "0" + hexStr;
        }

        int len = hexStr.length();
        byte[] bytes = new byte[len / 2];

        for (int i = 0; i < len; i += 2) {
            //可能会抛出异常 NumberFormatException ，但是 matches 提前处理了。
            try {
                bytes[i / 2] = (byte) Integer.parseInt(hexStr.substring(i, i + 2), 16);
            } catch (NumberFormatException e) {
                System.err.println("16进制字符串转换失败:"+hexStr);
                e.printStackTrace();
                return null;
            }
        }

        return bytes;
    }
    /**
     * Hex的字符串必须为十六进制的字符，否则会抛出异常。Hex的范围为0x00到0xFF。
     *
     * Hex字符串转byte
     * @param inHex 待转换的Hex字符串
     * @return  转换后的byte
     */
    public static byte hexToByte(String inHex) throws NumberFormatException{
        int i = Integer.parseInt(inHex, 16);
        return (byte)Integer.parseInt(inHex,16);
    }


    public static String getBinaryStrFromByte(byte b){
        String result ="";
        byte a = b; ;
        for (int i = 0; i < 8; i++){
            byte c=a;
            a=(byte)(a>>1);//每移一位如同将10进制数除以2并去掉余数。
            a=(byte)(a<<1);
            if(a==c){
                result="0"+result;
            }else{
                result="1"+result;
            }
            a=(byte)(a>>1);
        }
        return result;
    }

    //2024-06-19 OK
    //将16进制字符串转换为ASCII字符串 eg: 313233343536-->123456
    public static String hexStrToASCII(String hexStr){
        // 检查输入是否为空或长度小于1
        if (hexStr == null || hexStr.length() < 1) {
            System.err.println("输入的参数异常:"+hexStr);
            return null;
        }

        // 检查输入是否为有效的16进制字符串
        if (!hexStr.matches("[0-9A-Fa-f]+") || hexStr.length() % 2 != 0) {
            System.err.println("输入不是有效的16进制字符串:"+hexStr);
            return null;
        }

        StringBuilder output = new StringBuilder();
        try {
            for (int i = 0; i < hexStr.length(); i += 2) {
                // 提取两个字符
                String str = hexStr.substring(i, i + 2);
                // 转换为整数并追加到输出中
                output.append((char) Integer.parseInt(str, 16));
            }
        } catch (NumberFormatException e) {
            System.err.println("16进制字符串转换失败:"+hexStr);
            e.printStackTrace();
            return null;
        }

        return output.toString();
    }
    //beeboxes serial read
    public static String bytes2HexStr(byte[] src) {
        StringBuilder builder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return "";
        }
        char[] buffer = new char[2];
        for (int i = 0; i < src.length; i++) {
            buffer[0] = forDigit((src[i] >>> 4) & 0x0F, 16);
            buffer[1] = forDigit(src[i] & 0x0F, 16);
            builder.append(buffer);
        }
        return builder.toString();
    }
    private static char forDigit(int digit, int radix) {
        if ((digit >= radix) || (digit < 0)) {
            return '\0';
        }
        if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) {
            return '\0';
        }
        if (digit < 10) {
            return (char) ('0' + digit);
        }
        return (char) ('A' - 10 + digit);
    }

    /**
     * 十进制 byte[] 转 字符串,且去掉尾部的 0 。暂时没有考虑尾部多少个0
     * eg: byte[] origin = {45, 45, 49, 42, 42, 49};//--1**1
     *  byte[] byteArray = {72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 0, 0, 0, 0, 65, 66, 67,0,0,0,0};
     * byte[] origin = {45,45,50,48,53,42,42,49,48,48,56,49,0,0,0,0};//--205**10081    
     * @param byteArray
     * @return
     */
    public static String decBytesToStringSkipTail0(byte[] byteArray) {
        if (byteArray == null || byteArray.length < 1) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        int i = byteArray.length - 1;
        while (i >= 0 && byteArray[i] == 0) {
            i--;
        }
        for (int j = 0; j <= i; j++) {
            char c = (char)byteArray[j];
            sb.append(c);
        }
        return sb.toString();
    }

    /**
     * 十进制 byte[] 转 字符串
     * //        byte[] origin = {45, 45, 49, 42, 42, 49};//--1**1
     * //        byte[] origin = {45,45,50,48,57,42,42,54,57,53,54};//--209**6956
     * @param byteArray
     * @return
     */
    public static String decBytesToString(byte[] byteArray) {
        if (byteArray == null || byteArray.length < 1) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < byteArray.length; i++) {
            char c = (char) byteArray[i];
            sb.append(c);
        }
        return sb.toString();
    }

}
